/*
*************************************************************************
**  $Header: Community.CsharpSqlite/src/_Custom.cs,v c8b9bab808c8 2010/02/22 12:54:28 Noah $
*************************************************************************
*/

using System;
using System.Diagnostics;
using System.IO;
using System.Management;
using System.Text;
using Community.CsharpSqlite.Entity;
#if !SQLITE_SILVERLIGHT
#endif


namespace Community.CsharpSqlite
{
    using sqlite3_value = Mem;

    public class Custom
    {
        public static int Atoi(byte[] inStr)
        {
            return Atoi(Encoding.UTF8.GetString(inStr, 0, inStr.Length));
        }

        public static int Atoi(string inStr)
        {
            int i;
            for (i = 0; i < inStr.Length; i++)
            {
                if (!SqliteInt.Sqlite3Isdigit(inStr[i]) && inStr[i] != '-') break;
            }
            int result = 0;

            return (Int32.TryParse(inStr.Substring(0, i), out result) ? result : 0);
        }

        public static void Fprintf(TextWriter tw, string zFormat, params object[] ap)
        {
            tw.Write(Print.Sqlite3_mprintf(zFormat, ap));
        }

        public static void Printf(string zFormat, params object[] ap)
        {
            Console.Out.Write(Print.Sqlite3_mprintf(zFormat, ap));
        }


        //Byte Buffer Testing

        public static int Memcmp(byte[] bA, byte[] bB, int Limit)
        {
            if (bA.Length < Limit) return (bA.Length < bB.Length) ? -1 : +1;
            if (bB.Length < Limit) return +1;
            for (int i = 0; i < Limit; i++)
            {
                if (bA[i] != bB[i]) return (bA[i] < bB[i]) ? -1 : 1;
            }
            return 0;
        }

        //Byte Buffer  & String Testing
        public static int Memcmp(byte[] bA, string B, int Limit)
        {
            if (bA.Length < Limit) return (bA.Length < B.Length) ? -1 : +1;
            if (B.Length < Limit) return +1;
            for (int i = 0; i < Limit; i++)
            {
                if (bA[i] != B[i]) return (bA[i] < B[i]) ? -1 : 1;
            }
            return 0;
        }

        //Byte Buffer  & String Testing
        public static int Memcmp(string A, byte[] bB, int Limit)
        {
            if (A.Length < Limit) return (A.Length < bB.Length) ? -1 : +1;
            if (bB.Length < Limit) return +1;
            for (int i = 0; i < Limit; i++)
            {
                if (A[i] != bB[i]) return (A[i] < bB[i]) ? -1 : 1;
            }
            return 0;
        }

        //String with Offset & String Testing
        public static int Memcmp(byte[] a, int Offset, byte[] b, int Limit)
        {
            if (a.Length < Offset + Limit) return (a.Length - Offset < b.Length) ? -1 : +1;
            if (b.Length < Limit) return +1;
            for (int i = 0; i < Limit; i++)
            {
                if (a[i + Offset] != b[i]) return (a[i + Offset] < b[i]) ? -1 : 1;
            }
            return 0;
        }

        public static int Memcmp(string a, int Offset, byte[] b, int Limit)
        {
            if (a.Length < Offset + Limit) return (a.Length - Offset < b.Length) ? -1 : +1;
            if (b.Length < Limit) return +1;
            for (int i = 0; i < Limit; i++)
            {
                if (a[i + Offset] != b[i]) return (a[i + Offset] < b[i]) ? -1 : 1;
            }
            return 0;
        }

        public static int Memcmp(byte[] a, int Offset, string b, int Limit)
        {
            if (a.Length < Offset + Limit) return (a.Length - Offset < b.Length) ? -1 : +1;
            if (b.Length < Limit) return +1;
            for (int i = 0; i < Limit; i++)
            {
                if (a[i + Offset] != b[i]) return (a[i + Offset] < b[i]) ? -1 : 1;
            }
            return 0;
        }


        //String Testing
        public static int Memcmp(string A, string B, int Limit)
        {
            if (A.Length < Limit) return (A.Length < B.Length) ? -1 : +1;
            if (B.Length < Limit) return +1;
            for (int i = 0; i < Limit; i++)
            {
                if (A[i] != B[i]) return (A[i] < B[i]) ? -1 : 1;
            }
            return 0;
        }

        // ----------------------------
        // ** Convertion routines
        // ----------------------------
        private static string vaFORMAT;
        private static int vaNEXT;

        public static void VaStart(object[] ap, string zFormat)
        {
            vaFORMAT = zFormat;
            vaNEXT = 0;
        }

        public static object VaArg(object[] ap, string sysType)
        {
            vaNEXT += 1;
            if (ap == null || ap.Length == 0)
                return "";
            switch (sysType)
            {
                case "double":
                    return Convert.ToDouble(ap[vaNEXT - 1]);
                case "long":
                case "long int":
                case "longlong int":
                case "i64":
                    if (ap[vaNEXT - 1].GetType().BaseType.Name == "Object")
                        return (long) (ap[vaNEXT - 1].GetHashCode());
                    ;
                    return Convert.ToInt64(ap[vaNEXT - 1]);
                case "int":
                    if (Convert.ToInt64(ap[vaNEXT - 1]) > 0 && (Convert.ToUInt32(ap[vaNEXT - 1]) > Int32.MaxValue))
                        return (Int32) (Convert.ToUInt32(ap[vaNEXT - 1]) - UInt32.MaxValue - 1);
                    else return Convert.ToInt32(ap[vaNEXT - 1]);
                case "SrcList":
                    return ap[vaNEXT - 1];
                case "char":
                    if (ap[vaNEXT - 1].GetType().Name == "Int32" && (int) ap[vaNEXT - 1] == 0)
                    {
                        return '0';
                    }
                    else
                    {
                        if (ap[vaNEXT - 1].GetType().Name == "Int64")
                            if ((long) ap[vaNEXT - 1] == 0)
                            {
                                return '0';
                            }
                            else return (char) ((long) ap[vaNEXT - 1]);
                        else
                            return (char) ap[vaNEXT - 1];
                    }
                case "char*":
                case "string":
                    if (ap[vaNEXT - 1] == null)
                    {
                        return "NULL";
                    }
                    else
                    {
                        if (ap[vaNEXT - 1].GetType().Name == "Byte[]")
                            if (Encoding.UTF8.GetString((byte[]) ap[vaNEXT - 1], 0, ((byte[]) ap[vaNEXT - 1]).Length) ==
                                "\0")
                                return "";
                            else
                                return Encoding.UTF8.GetString((byte[]) ap[vaNEXT - 1], 0,
                                                               ((byte[]) ap[vaNEXT - 1]).Length);
                        else if (ap[vaNEXT - 1].GetType().Name == "Int32")
                            return null;
                        else if (ap[vaNEXT - 1].GetType().Name == "StringBuilder")
                            return ap[vaNEXT - 1].ToString();
                        else return ap[vaNEXT - 1];
                    }
                case "byte[]":
                    if (ap[vaNEXT - 1] == null)
                    {
                        return null;
                    }
                    else
                    {
                        return ap[vaNEXT - 1];
                    }
                case "byte[][]":
                    if (ap[vaNEXT - 1] == null)
                    {
                        return null;
                    }
                    else
                    {
                        return ap[vaNEXT - 1];
                    }
                case "int[]":
                    if (ap[vaNEXT - 1] == null)
                    {
                        return "NULL";
                    }
                    else
                    {
                        return ap[vaNEXT - 1];
                    }
                case "Token":
                    return ap[vaNEXT - 1];
                case "u3216":
                    return Convert.ToUInt16(ap[vaNEXT - 1]);
                case "uint":
                case "unsigned int":
                    if (ap[vaNEXT - 1].GetType().IsClass)
                    {
                        return ap[vaNEXT - 1].GetHashCode();
                    }
                    else
                    {
                        return Convert.ToUInt32(ap[vaNEXT - 1]);
                    }
                case "ulong":
                case "unsigned long":
                case "unsigned long int":
                    if (ap[vaNEXT - 1].GetType().IsClass)
                        return Convert.ToUInt64(ap[vaNEXT - 1].GetHashCode());
                    else
                        return Convert.ToUInt64(ap[vaNEXT - 1]);
                case "sqlite3_mem_methods":
                    return (sqlite3_mem_methods) ap[vaNEXT - 1];
                case "void_function":
                    return ap[vaNEXT - 1];
                case "MemPage":
                    return ap[vaNEXT - 1];
                default:
                    Debugger.Break();
                    return ap[vaNEXT - 1];
            }
        }

        public static void VaEnd(object[] ap)
        {
            ap = null;
            vaFORMAT = "";
        }


        public static tm Localtime(long baseTime)
        {
            var RefTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            RefTime = RefTime.AddSeconds(Convert.ToDouble(baseTime)).ToLocalTime();
            var tm = new tm();
            tm.tm_sec = RefTime.Second;
            tm.tm_min = RefTime.Minute;
            tm.tm_hour = RefTime.Hour;
            tm.tm_mday = RefTime.Day;
            tm.tm_mon = RefTime.Month;
            tm.tm_year = RefTime.Year;
            tm.tm_wday = (int) RefTime.DayOfWeek;
            tm.tm_yday = RefTime.DayOfYear;
            tm.tm_isdst = RefTime.IsDaylightSavingTime() ? 1 : 0;
            return tm;
        }

        public static long ToUnixtime(DateTime date)
        {
            var unixStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            TimeSpan timeSpan = date - unixStartTime;
            return Convert.ToInt64(timeSpan.TotalSeconds);
        }

        public static DateTime ToCSharpTime(long unixTime)
        {
            var unixStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return unixStartTime.AddSeconds(Convert.ToDouble(unixTime));
        }

      

        // Example (C#)
        public static int GetbytesPerSector(StringBuilder diskPath)
        {
#if !SQLITE_SILVERLIGHT
            var mosLogicalDisks =
                new ManagementObjectSearcher("select * from Win32_LogicalDisk where DeviceID = '" +
                                             diskPath.ToString().Remove(diskPath.Length - 1, 1) + "'");
            try
            {
                foreach (ManagementObject moLogDisk in mosLogicalDisks.Get())
                {
                    var mosDiskDrives =
                        new ManagementObjectSearcher("select * from Win32_DiskDrive where SystemName = '" +
                                                     moLogDisk["SystemName"] + "'");
                    foreach (ManagementObject moPDisk in mosDiskDrives.Get())
                    {
                        return int.Parse(moPDisk["BytesPerSector"].ToString());
                    }
                }
            }
            catch
            {
            }
            return 4096;
#else
      return 4096;
#endif
        }

        public static void Swap<T>(ref T A, ref T B)
        {
            T t = A;
            A = B;
            B = t;
        }

        private static void x_CountStep(
            sqlite3_context context,
            int argc,
            sqlite3_value[] argv
            )
        {
            SumCtx p;

            int type;
            Debug.Assert(argc <= 1);
            Mem pMem = Sqlite3.sqlite3_aggregate_context(context, 1); //sizeof(*p));
            if (pMem._SumCtx == null) pMem._SumCtx = new SumCtx();
            p = pMem._SumCtx;
            if (p.Context == null) p.Context = pMem;
            if (argc == 0 || FundamentalDataType.SQLITE_NULL == Sqlite3.sqlite3_value_type(argv[0]))
            {
                p.cnt++;
                p.iSum += 1;
            }
            else
            {
                type = Sqlite3.sqlite3_value_numeric_type(argv[0]);
                if (p != null && type != FundamentalDataType.SQLITE_NULL)
                {
                    p.cnt++;
                    if (type == FundamentalDataType.SQLITE_INTEGER)
                    {
                        long v = Sqlite3.sqlite3_value_int64(argv[0]);
                        if (v == 40 || v == 41)
                        {
                            Sqlite3.sqlite3_result_error(context, "value of " + v + " handed to x_count", -1);
                            return;
                        }
                        else
                        {
                            p.iSum += v;
                            if (!(p.approx | p.overflow != 0))
                            {
                                long iNewSum = p.iSum + v;
                                var s1 = (int) (p.iSum >> (sizeof (long)*8 - 1));
                                var s2 = (int) (v >> (sizeof (long)*8 - 1));
                                var s3 = (int) (iNewSum >> (sizeof (long)*8 - 1));
                                p.overflow = ((s1 & s2 & ~s3) | (~s1 & ~s2 & s3)) != 0 ? 1 : 0;
                                p.iSum = iNewSum;
                            }
                        }
                    }
                    else
                    {
                        p.rSum += Sqlite3.sqlite3_value_double(argv[0]);
                        p.approx = true;
                    }
                }
            }
        }

        private static void x_CountFinalize(sqlite3_context context)
        {
            SumCtx p;
            Mem pMem = Sqlite3.sqlite3_aggregate_context(context, 0);
            p = pMem._SumCtx;
            if (p != null && p.cnt > 0)
            {
                if (p.overflow != 0)
                {
                    Sqlite3.sqlite3_result_error(context, "integer overflow", -1);
                }
                else if (p.approx)
                {
                    Sqlite3.sqlite3_result_double(context, p.rSum);
                }
                else if (p.iSum == 42)
                {
                    Sqlite3.sqlite3_result_error(context, "x_count totals to 42", -1);
                }
                else
                {
                    Sqlite3.sqlite3_result_int64(context, p.iSum);
                }
            }
        }

#if SQLITE_MUTEX_W32
//---------------------WIN32 Definitions
static int GetCurrentThreadId()
{
return Thread.CurrentThread.ManagedThreadId;
}
static long InterlockedIncrement(long location)
{
Interlocked.Increment(ref  location);
return location;
}

static void EnterCriticalSection(Mutex mtx)
{
Monitor.Enter(mtx);
}
static void InitializeCriticalSection(Mutex mtx)
{
Monitor.Enter(mtx);
}
static void DeleteCriticalSection(Mutex mtx)
{
Monitor.Exit(mtx);
}
static void LeaveCriticalSection(Mutex mtx)
{
Monitor.Exit(mtx);
}

}
#endif
    }
}